Programming and Data Analysis¶

Project: Taiwan Referendum 2021

Kuo, Yao-Jen yaojenkuo@ntu.edu.tw from DATAINPOINT

In [1]:
# Importing libraries/functions the project needs
import os
import numpy as np
import pandas as pd
import folium

Importing Data¶

Data source¶

110 年公民投票全國性公投:https://www.cec.gov.tw/pc/zh_TW/index.html

The original data format is Excel workbook¶

We can use pd.read_excel for importing.

Importing the data of 臺北市¶

Check the list of worksheets before importing.

In [2]:
file_name = "data/表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls"
excel_file = pd.ExcelFile(file_name)
print(excel_file.sheet_names)
['第17案', '第18案', '第19案', '第20案']
In [3]:
df = pd.read_excel(excel_file)
df.head()
Out[3]:
110年全國性公民投票第17案在臺北市各投開票所得票數一覽表 Unnamed: 1 Unnamed: 2 Unnamed: 3 Unnamed: 4 Unnamed: 5 Unnamed: 6 Unnamed: 7 Unnamed: 8 Unnamed: 9 Unnamed: 10 Unnamed: 11 Unnamed: 12
0 鄉(鎮、市、區)別 村里別 投開票所別 得票情形 NaN A\n有效票數\nA=1+2 B\n無效票數 C\n投票數\nC=A+B D\n已領未投票數\nD=E-C E\n發出票數\nE=C+D F\n用餘票數 G\n投票權人數\nG=E+F H\n投票率\nH=C÷G\n(%)
1 NaN NaN NaN 1\n同意 2\n不同意 NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 總 計 NaN NaN 514232 490692 1004924 9609 1014533 192 1014725 1140691 2155416 47.07

We can specify which sheet to import via sheet_name parameter¶

In [4]:
for sheetName in excel_file.sheet_names:
    df = pd.read_excel(file_name, sheet_name=sheetName)
    print(f"Shape of {sheetName}: {df.shape}")
Shape of 第17案: (1762, 13)
Shape of 第18案: (1762, 13)
Shape of 第19案: (1762, 13)
Shape of 第20案: (1762, 13)

The sheet_name parameter can also accept integer as input¶

In [5]:
for i in range(len(excel_file.sheet_names)):
    df = pd.read_excel(file_name, sheet_name=i)
    print(f"Shape of the {i}th sheet: {df.shape}")
Shape of the 0th sheet: (1762, 13)
Shape of the 1th sheet: (1762, 13)
Shape of the 2th sheet: (1762, 13)
Shape of the 3th sheet: (1762, 13)

Wrangling Data¶

Once the import part is done, it is time to wrangle the messy spreashets into a tidy data format¶

Tidy datasets are all alike, but every messy dataset is messy in its own way

Hadley Wickham

What is tidy data?¶

There are three interrelated rules which make a dataset tidy:

  1. Each variable must have its own column.
  2. Each observation must have its own row.
  3. Each value must have its own cell.

Source: https://vita.had.co.nz/papers/tidy-data.pdf

Why tidy data?¶

Simply put, once our data is in tidy format, it is easy to use and quite convenient to tranform into the designated format of visualization or modeling functions for the next stage of data science project.

What makes our original workbooks messy?¶

  • Combined cells
  • Missing values
  • Summations within observations
  • Value in variable names

Using skiprows parameter to skip those combined cells while importing workbook¶

In [6]:
df = pd.read_excel(file_name, skiprows=[0, 1, 3, 4])
In [7]:
df.head()
Out[7]:
Unnamed: 0 Unnamed: 1 Unnamed: 2 1\n同意 2\n不同意 Unnamed: 5 Unnamed: 6 Unnamed: 7 Unnamed: 8 Unnamed: 9 Unnamed: 10 Unnamed: 11 Unnamed: 12
0 總 計 NaN NaN 514232 490692 1004924 9609 1014533 192 1014725 1140691 2155416 47.07
1 松山區 NaN NaN 42583 37246 79829 743 80572 4 80576 82388 162964 49.44
2 NaN 莊敬里 1.0 285 251 536 1 537 0 537 537 1074 50.00
3 NaN 莊敬里 2.0 254 237 491 9 500 0 500 638 1138 43.94
4 NaN 莊敬里 3.0 228 198 426 5 431 0 431 652 1083 39.80

Updating columns attributes with new column names and drop columns¶

In [8]:
df = df.iloc[:, :5]
df.columns = ["town", "village", "office", "agree", "disagree"]
df.head()
Out[8]:
town village office agree disagree
0 總 計 NaN NaN 514232 490692
1 松山區 NaN NaN 42583 37246
2 NaN 莊敬里 1.0 285 251
3 NaN 莊敬里 2.0 254 237
4 NaN 莊敬里 3.0 228 198

Using fillna() to forward-fill town values¶

ffill: propagate last valid observation forward to next valid.

In [9]:
filled_towns = df["town"].fillna(method='ffill')
df = df.assign(town=filled_towns)
df.head()
Out[9]:
town village office agree disagree
0 總 計 NaN NaN 514232 490692
1 松山區 NaN NaN 42583 37246
2 松山區 莊敬里 1.0 285 251
3 松山區 莊敬里 2.0 254 237
4 松山區 莊敬里 3.0 228 198

Removing subtotals and totals via dropna()¶

  • To comply with the tidy data rule.
  • To avoid wrong summations.
In [10]:
df = df.dropna()
df.head()
Out[10]:
town village office agree disagree
2 松山區 莊敬里 1.0 285 251
3 松山區 莊敬里 2.0 254 237
4 松山區 莊敬里 3.0 228 198
5 松山區 莊敬里 4.0 310 251
6 松山區 東榮里 5.0 333 337

Removing extra spaces in town via str.replace()¶

In [11]:
print(df['town'].unique())
stripped_town = df['town'].str.strip()
df = df.assign(town=stripped_town)
print(df['town'].unique())
['    松山區' '    信義區' '    大安區' '    中山區' '    中正區' '    大同區' '    萬華區'
 '    文山區' '    南港區' '    內湖區' '    士林區' '    北投區']
['松山區' '信義區' '大安區' '中山區' '中正區' '大同區' '萬華區' '文山區' '南港區' '內湖區' '士林區' '北投區']

Transposing wide format into long format¶

In [12]:
df_long = pd.melt(df, id_vars=["town", "village", "office"],
                  var_name='variable',
                  value_name='votes'
                 )
df_long.head()
Out[12]:
town village office variable votes
0 松山區 莊敬里 1.0 agree 285
1 松山區 莊敬里 2.0 agree 254
2 松山區 莊敬里 3.0 agree 228
3 松山區 莊敬里 4.0 agree 310
4 松山區 東榮里 5.0 agree 333

Adjusting column data type¶

In [13]:
df_long = df_long.astype({"office": int})
df_long.dtypes
Out[13]:
town        object
village     object
office       int64
variable    object
votes        int64
dtype: object

Assembling codes¶

Define a function called melt_tidy_dataframe() which assembles the previous cells¶

In [14]:
def melt_tidy_dataframe(df):
    # updating columns attributes 
    df = df.iloc[:, :5]
    df.columns = ["town", "village", "office", "agree", "disagree"]
    # forward-fill town values
    filled_towns = df['town'].fillna(method='ffill')
    df = df.assign(town=filled_towns)
    # removing subtotals and totals
    df = df.dropna()
    # removing extra spaces
    stripped_town = df['town'].str.strip()
    df = df.assign(town=stripped_town)
    # transposing
    df_long = pd.melt(df, id_vars=["town", "village", "office"],
                      var_name='variable',
                      value_name='votes'
                     )
    # adjusting data type
    df_long = df_long.astype({"office": int})
    return df_long

Retrieving file names¶

In [15]:
list_dir = os.listdir("data")
file_names = [file for file in list_dir if ".xls" in file and ".xlsx" not in file]
print(file_names)
['表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls', '表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls', '表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls', '表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls', '表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls', '表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls', '表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls', '表5-新北市-全國性公民投票得票數一覽表(投開票所).xls', '表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls', '表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls', '表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls']

Applying melt_tidy_dataframe() on all workbooks¶

In [16]:
sheet_order_case_number = {i: i+17 for i in range(4)}
print(sheet_order_case_number)
{0: 17, 1: 18, 2: 19, 3: 20}
In [17]:
appended_df = pd.DataFrame()
for file_name in file_names:
    county = file_name.split("-")[1]
    for key, value in sheet_order_case_number.items():
        df = pd.read_excel(f"data/{file_name}", skiprows=[0, 1, 3, 4], sheet_name=key)
        melted_tidy_dataframe = melt_tidy_dataframe(df)
        melted_tidy_dataframe['county'] = county
        melted_tidy_dataframe['case'] = value
        appended_df = appended_df.append(melted_tidy_dataframe)
        print(f"Melting and tidying worksheet {key} of {file_name}...")
appended_df = appended_df.reset_index(drop=True) # reset index for the appended dataframe
Melting and tidying worksheet 0 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
In [18]:
appended_df.head()
Out[18]:
town village office variable votes county case
0 臺東市 文化里 1 agree 138 臺東縣 17
1 臺東市 民族里 2 agree 102 臺東縣 17
2 臺東市 民族里 3 agree 161 臺東縣 17
3 臺東市 自強里 4 agree 236 臺東縣 17
4 臺東市 自強里 5 agree 248 臺東縣 17
In [19]:
appended_df.tail()
Out[19]:
town village office variable votes county case
139827 牡丹鄉 牡丹村 708 disagree 28 屏東縣 20
139828 牡丹鄉 東源村 709 disagree 25 屏東縣 20
139829 牡丹鄉 旭海村 710 disagree 30 屏東縣 20
139830 牡丹鄉 高士村 711 disagree 29 屏東縣 20
139831 牡丹鄉 四林村 712 disagree 22 屏東縣 20

Define a class TaiwanReferendum2021 to make the above codes more organized¶

In [20]:
class TaiwanRefendum2021:
    def __init__(self):
        self.sheet_order_case_number = {i: i+17 for i in range(4)}
        self.file_names = [file for file in os.listdir("data") if ".xls" in file and ".xlsx" not in file]
    def melt_tidy_dataframe(self, df):
        # updating columns attributes 
        df = df.iloc[:, :5]
        df.columns = ["town", "village", "office", "agree", "disagree"]
        # forward-fill town values
        filled_towns = df['town'].fillna(method='ffill')
        df = df.assign(town=filled_towns)
        # removing subtotals and totals
        df = df.dropna()
        # removing extra spaces
        stripped_town = df['town'].str.strip()
        df = df.assign(town=stripped_town)
        # transposing
        df_long = pd.melt(df, id_vars=["town", "village", "office"],
                          var_name='variable',
                          value_name='votes'
                         )
        # adjusting data type
        df_long = df_long.astype({"office": int})
        return df_long
    def create_referendum_dataframe(self):
        appended_df = pd.DataFrame()
        for file_name in self.file_names:
            county = file_name.split("-")[1]
            for key, value in self.sheet_order_case_number.items():
                df = pd.read_excel(f"data/{file_name}", skiprows=[0, 1, 3, 4], sheet_name=key)
                melted_tidy_dataframe = self.melt_tidy_dataframe(df)
                melted_tidy_dataframe['county'] = county
                melted_tidy_dataframe['case'] = value
                appended_df = appended_df.append(melted_tidy_dataframe)
                print(f"Melting and tidying worksheet {key} of {file_name}...")
        appended_df = appended_df.reset_index(drop=True) # reset index for the appended dataframe
        out_df = appended_df[["county", "town", "village", "office", "case", "variable", "votes"]]
        return out_df

Use TaiwanReferendum2021 class to generate the compact DataFrame¶

In [21]:
taiwan_referendum_2021 = TaiwanRefendum2021()
referendum_dataframe = taiwan_referendum_2021.create_referendum_dataframe()
Melting and tidying worksheet 0 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-基隆市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-雲林縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-嘉義市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-新竹縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-澎湖縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-金門縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-嘉義縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-高雄市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-新竹市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-花蓮縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-南投縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-苗栗縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-桃園市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-宜蘭縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺南市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-新北市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-臺中市-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-連江縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-彰化縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 0 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 1 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 2 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
Melting and tidying worksheet 3 of 表5-屏東縣-全國性公民投票得票數一覽表(投開票所).xls...
In [22]:
referendum_dataframe
Out[22]:
county town village office case variable votes
0 臺東縣 臺東市 文化里 1 17 agree 138
1 臺東縣 臺東市 民族里 2 17 agree 102
2 臺東縣 臺東市 民族里 3 17 agree 161
3 臺東縣 臺東市 自強里 4 17 agree 236
4 臺東縣 臺東市 自強里 5 17 agree 248
... ... ... ... ... ... ... ...
139827 屏東縣 牡丹鄉 牡丹村 708 20 disagree 28
139828 屏東縣 牡丹鄉 東源村 709 20 disagree 25
139829 屏東縣 牡丹鄉 旭海村 710 20 disagree 30
139830 屏東縣 牡丹鄉 高士村 711 20 disagree 29
139831 屏東縣 牡丹鄉 四林村 712 20 disagree 22

139832 rows × 7 columns

Done wrangling the Taiwan referendum 2021 data!¶

Source: https://giphy.com/

Summarizing results¶

In [23]:
votes_by_village = referendum_dataframe.groupby(["county", "case", "variable"])["votes"].sum()
votes_by_village = pd.DataFrame(votes_by_village).reset_index()
votes_by_village
Out[23]:
county case variable votes
0 南投縣 17 agree 82471
1 南投縣 17 disagree 73365
2 南投縣 18 agree 84903
3 南投縣 18 disagree 70911
4 南投縣 19 agree 84360
... ... ... ... ...
171 高雄市 18 disagree 588302
172 高雄市 19 agree 398161
173 高雄市 19 disagree 588679
174 高雄市 20 agree 392910
175 高雄市 20 disagree 593239

176 rows × 4 columns

In [24]:
total_votes_by_village = referendum_dataframe.groupby(["county", "case"])["votes"].sum()
total_votes_by_village = pd.DataFrame(total_votes_by_village).reset_index()
total_votes_by_village
Out[24]:
county case votes
0 南投縣 17 155836
1 南投縣 18 155814
2 南投縣 19 155893
3 南投縣 20 155785
4 嘉義市 17 92209
... ... ... ...
83 雲林縣 20 201035
84 高雄市 17 986618
85 高雄市 18 986292
86 高雄市 19 986840
87 高雄市 20 986149

88 rows × 3 columns

Calculating percentage¶

In [25]:
merged_df = pd.merge(votes_by_village, total_votes_by_village, 
                     left_on=["county", "case"],
                     right_on=["county", "case"])
percentages = merged_df["votes_x"] / merged_df["votes_y"]
In [26]:
percentage_df = pd.DataFrame()
percentage_df["county"] = merged_df["county"].values
percentage_df["case"] = merged_df["case"].values
percentage_df["variable"] = merged_df["variable"].values
percentage_df["percentage"] = percentages
percentage_df
Out[26]:
county case variable percentage
0 南投縣 17 agree 0.529217
1 南投縣 17 disagree 0.470783
2 南投縣 18 agree 0.544900
3 南投縣 18 disagree 0.455100
4 南投縣 19 agree 0.541140
... ... ... ... ...
171 高雄市 18 disagree 0.596479
172 高雄市 19 agree 0.403471
173 高雄市 19 disagree 0.596529
174 高雄市 20 agree 0.398429
175 高雄市 20 disagree 0.601571

176 rows × 4 columns

In [27]:
counties = percentage_df["county"].map(lambda x: x.replace("臺", "台"))
counties = counties.map(lambda x: x.replace("桃園市", "桃園縣"))
percentage_viz = pd.DataFrame()
percentage_viz["county"] = counties.values
percentage_viz["case"] = percentage_df["case"].values
percentage_viz["variable"] = percentage_df["variable"].values
percentage_viz["percentage"] = np.round(percentage_df["percentage"].values * 100, 2)
percentage_viz
Out[27]:
county case variable percentage
0 南投縣 17 agree 52.92
1 南投縣 17 disagree 47.08
2 南投縣 18 agree 54.49
3 南投縣 18 disagree 45.51
4 南投縣 19 agree 54.11
... ... ... ... ...
171 高雄市 18 disagree 59.65
172 高雄市 19 agree 40.35
173 高雄市 19 disagree 59.65
174 高雄市 20 agree 39.84
175 高雄市 20 disagree 60.16

176 rows × 4 columns

In [28]:
def show_percentage_on_map(case_num, variable):
    village_geo = "https://raw.githubusercontent.com/g0v/twgeojson/master/json/twCounty2010.geo.json"
    m = folium.Map(location=[24, 123], zoom_start=7)
    if variable == "agree":
        color_brewer = "Blues"
    else:
        color_brewer = "Greens"
    folium.Choropleth(
        geo_data=village_geo,
        name="choropleth",
        data=percentage_viz[(percentage_viz["case"] == case_num) & (percentage_viz["variable"] == variable)],
        columns=["county", "percentage"],
        key_on="feature.properties.COUNTYNAME",
        fill_color=color_brewer,
        fill_opacity=0.7,
        line_opacity=0.2,
        legend_name=f"Case{case_num} {variable} Percentage (%)",
    ).add_to(m)
    folium.LayerControl().add_to(m)
    return m
In [29]:
m = show_percentage_on_map(17, "disagree")
m
Out[29]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [30]:
m = show_percentage_on_map(18, "agree")
m
Out[30]:
Make this Notebook Trusted to load map: File -> Trust Notebook